package com.tzu.ssl;

import sun.security.tools.keytool.CertAndKeyGen;
import sun.security.x509.X500Name;

import java.io.FileOutputStream;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.Date;

/**
 * SSL工具类
 */
public class SSLTools {

    /**
     * SSL协议版本 SSLv1 / / 实际从未公开发布。<br>
     * SSLv2 1995 弃用 IETF已于2011年弃用。<br>
     * SSLv3 1996 弃用<br>
     * IETF已于2015年弃用。<br>
     * TLSv1.0 1999 兼容 - <br>
     * TLSv1.1 2006 兼容 - <br>
     * TLSv1.2 2008 主推 目前最新可用版本<br>
     * TLSv1.3 / / 2016开始草案制定<br>
     */
    public static class SSLVersion {
        public static final String TLS_V12 = "TLSv1.2";
        public static final String TLS_V13 = "TLSv1.3";
    }

    /**
     * .DER .CER，文件是二进制格式，只保存证书，不保存私钥。<br>
     * .PEM，一般是文本格式，可保存证书，可保存私钥。<br>
     * .CRT，可以是二进制格式，可以是文本格式，与 .DER 格式相同，不保存私钥。 <br>
     * .PFX .P12，(PKCS12)二进制格式，同时包含证书和私钥，一般有密码保护。<br>
     * .JKS，二进制格式，同时包含证书和私钥，一般有密码保护。<br>
     */
    public static class KeyStoreType {
        //        public static final String CER = "CER";
//        public static final String PEM = "PEM";
        //用于携带私有证书密钥对（加密或未加密）。
//        public static final String PKCS8 = "PKCS8";
        //定义一种文件格式，通常用于存储私钥以及随附的公钥证书，并使用基于密码的对称密钥进行保护。
        public static final String PKCS12 = "PKCS12";
        public static final String JKS = "JKS";
    }

    /**
     * 签名算法
     * https://blog.csdn.net/caiandyong/article/details/50282889
     */
    public static class SignAlgo {

        /**
         * 密钥长度：512-65536（64的整数倍）
         * 默认长度：1024
         * 签名长度：同密钥
         */
        public static final String DSA = "DSA";
        public static final int DSA_DEF_LENGTH = 1024;
        public static final String SHA1_DSA = "SHA1withDSA";


        /**
         * 密钥长度：512-65536（64的整数倍）
         * 默认长度：1024
         * 签名长度：同密钥
         */
        public static final String RSA = "RSA";
        public static final int RSA_DEF_LENGTH = 1024;
        public static final String SHA1_RSA = "SHA1WithRSA";
        public static final String MD5_RSA = "MD5withRSA";

        /**
         * 密钥长度：112-571
         * 默认长度：256
         * 签名长度：SHA1withECDSA-160，SHA256withECDSA-256，SHA384withECDSA-384，SHA512withECDSA-512
         */
        public static final String EC = "EC";
        public static final int EC_DEF_LENGTH = 256;
        public static final String SHA1_ECDSA = "SHA1withECDSA";
        public static final String SHA256_ECDSA = "SHA256withECDSA";
        public static final String SHA384_ECDSA = "SHA384withECDSA";
        public static final String SHA512_ECDSA = "SHA512withECDSA";

    }


    public static final String SUN_X509 = "SunX509";

    public static final String FILE_NAME_KEYSTORE = "ft_key.keystore";
    public static final String FILE_NAME_TRUSTSTORE = "ft_trust.keystore";
//    public static final String FILE_NAME_KEYSTORE_SERVER = "ft_server.keystore";
//    public static final String FILE_NAME_KEYSTORE_CLIENT = "ft_client.keystore";
//    public static final String FILE_NAME_CERT = "ft.cer";
//    public static final String FILE_NAME_PRIVATE = "ft_pri.key";
//    public static final String FILE_NAME_PUBLIC = "ft_pub.key";


    /**
     * 生成密钥库（密钥库包含公钥、私钥、证书）
     */
    public static KeyStore createKeyStore(KeyInfo keyInfo) throws GeneralSecurityException, IOException {
        //创建证书类型
        CertAndKeyGen keypair = new CertAndKeyGen(keyInfo.getKeyalg(), keyInfo.getSignAlgo());
        X500Name x500Name = new X500Name(keyInfo.getCommon(), keyInfo.getOrgUnit(), keyInfo.getOrg(), keyInfo.getCity(),
                keyInfo.getState(), keyInfo.getCountry());
        //证书位数
        keypair.generate(keyInfo.getKeysize());

        //证书链：x500，创建时间，有效期
        X509Certificate[] chain = new X509Certificate[1];
        chain[0] = keypair.getSelfCertificate(x500Name, new Date(), keyInfo.getValidity());

        // 密码
        char[] keypass = keyInfo.getKeypass().toCharArray();

        // 创建密钥库
        PrivateKey privateKey = keypair.getPrivateKey();

        PublicKey publicKey = keypair.getPublicKey();

        //密钥库
        String storeType = null == keyInfo.getKeyStoreType() ? KeyStore.getDefaultType() : keyInfo.getKeyStoreType();
        KeyStore keyStore = KeyStore.getInstance(storeType);
        //创建空密钥库
        keyStore.load(null, keypass);
        keyStore.setKeyEntry(keyInfo.getAlias(), privateKey, keypass, chain);


        // 保存密钥库
        try (FileOutputStream keystoreStream = new FileOutputStream(keyInfo.getKeyStorePath())) {
            keyStore.store(keystoreStream, keypass);
            keystoreStream.flush();
            keystoreStream.close();
            System.out.println("KeyStore create success");
        } catch (IOException e) {
            throw e;
        }

        return keyStore;
    }

    /**
     * 生成信任密钥库
     */
    public static void createTrustStore(KeyInfo keyInfo, KeyStore keyStore) throws GeneralSecurityException, IOException {
        //密钥库
        String storeType = null == keyInfo.getKeyStoreType() ? KeyStore.getDefaultType() : keyInfo.getKeyStoreType();
        // 密码
        char[] keypass = keyInfo.getKeypass().toCharArray();
        String alias = keyInfo.getAlias();
        Certificate certificate = keyStore.getCertificate(keyInfo.getAlias());

        KeyStore trustkeyStore = KeyStore.getInstance(storeType);
        trustkeyStore.load(null, keypass);
        trustkeyStore.setCertificateEntry(alias, certificate);
        try (FileOutputStream fos = new FileOutputStream(keyInfo.getTrustStorePath())) {
            trustkeyStore.store(fos, keypass);
        }
    }


    public static void makeSslFile(KeyInfo keyInfo) throws GeneralSecurityException, IOException {
        //创建密钥库
        KeyStore keyStore = createKeyStore(keyInfo);
        //创建信任库
        createTrustStore(keyInfo, keyStore);
    }


    // keytool -genkey -alias ftkey -keyalg RSA -keysize 1024 -validity 365
    // -keystore D:/TEST/ftkey.keystore -keypass 123456 -storepass 123456 -dname
    // "CN=ft,OU=ht304,O=casic,L=beijing,ST=beijing,C=CN"
    public static void main(String[] args) throws Exception {
        String keyStorePath = "D:\\TEST\\ssl\\test.keystore";
        String privatekey = "D:\\TEST\\ssl\\test_pri.txt";
        String publickey = "D:\\TEST\\ssl\\test_pub.txt";
        String cert = "D:\\TEST\\ssl\\test.cer";
        KeyInfo info = new KeyInfo("tzukey", "123456", SignAlgo.RSA, SignAlgo.SHA1_RSA, SignAlgo.RSA_DEF_LENGTH, keyStorePath, KeyStoreType.PKCS12);
        info.setKeypass("123456");
        //创建蜜月
        KeyStore keyStore = createKeyStore(info);

    }

}
